package com.xhwl.logistics.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.pojo.cent.sdata.Project;
import com.xhwl.common.query.cent.sdata.ProjectQuery;
import com.xhwl.common.utils.ChkUtil;
import com.xhwl.logistics.bo.VehicleAccessRecordBO;
import com.xhwl.logistics.bo.cent.VehicleIntegratedConfigBO;
import com.xhwl.logistics.bo.input.*;
import com.xhwl.logistics.component.SignForCoSon;
import com.xhwl.logistics.controller.VehicleAccessRecordController;
import com.xhwl.logistics.converter.ToPage;
import com.xhwl.logistics.converter.ToPageBO;
import com.xhwl.logistics.converter.mapstruct.VehicleAccessRecordConverter;
import com.xhwl.logistics.dao.mapper.IVehicleAccessRecordMapper;
import com.xhwl.logistics.dto.push.CarInDataCoSonDTO;
import com.xhwl.logistics.dto.push.CarOutDataCoSonDTO;
import com.xhwl.logistics.dto.query.VehicleAccessRecordSecondDTO;
import com.xhwl.logistics.entity.VehicleAccessRecord;
import com.xhwl.logistics.enums.VehicleCardTypeEnum;
import com.xhwl.logistics.po.VehicleAccessRecordPO;
import com.xhwl.logistics.service.IVehicleAccessRecordService;
import com.xhwl.logistics.service.cent.IProjectService;
import com.xhwl.logistics.service.cent.QueryDeviceService;
import com.xhwl.logistics.util.AboutDateUtil;
import com.xhwl.logistics.util.EscapeCharacter;
import com.xhwl.logistics.util.MathUtil;
import com.xhwl.logistics.util.StringUtils;
import com.xhwl.logistics.vo.AccessRecordTrendVo;
import com.xhwl.logistics.vo.AccessTrendQuery;
import com.xhwl.logistics.vo.VehicleAccessRecordSecondVO;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;


//@Service
public class VehicleAccessRecordServiceImpl extends ServiceImpl<IVehicleAccessRecordMapper, VehicleAccessRecord> implements IVehicleAccessRecordService {

    @Autowired
    private IVehicleAccessRecordMapper vehicleAccessRecordMapper;
    @Autowired
    private VehicleAccessRecordConverter vehicleAccessRecordConverter;
    @Autowired
    private SignForCoSon signForCoSon;
    @Autowired
    private QueryDeviceService queryDeviceService;
    @Autowired
    private ToPageBO toPageBO;

    @Autowired
    private ToPage toPage;
    @Autowired
    private VehicleAccessRecordController vehicleAccessRecordController;

    @Autowired
    private IProjectService iProjectService;

    @Override
    public IPage<VehicleAccessRecordBO> accessRecord(QueryVehicleAccessRecordBO queryVehicleAccessRecordBO, PageBO pageBO) {
        String orderColumn = queryVehicleAccessRecordBO.getOrderColumn();
        if (StringUtils.isNotBlank(orderColumn)) {
            //将前端传的驼峰命名法转换为满足数据中的字段形式
            queryVehicleAccessRecordBO.setOrderColumn(MathUtil.humpToUnderline(queryVehicleAccessRecordBO.getOrderColumn()));
        }
        //在查询条件的特殊字符前加上转义字符
        if(!StringUtils.isEmpty(queryVehicleAccessRecordBO.getPlateNumber())){
            queryVehicleAccessRecordBO.setPlateNumber(EscapeCharacter.escape(queryVehicleAccessRecordBO.getPlateNumber()));
        }
        IPage<VehicleAccessRecordPO> vehicleAccessRecordPOIPage = vehicleAccessRecordMapper.queryAccessRecords(pageBO.toPage(), queryVehicleAccessRecordBO);

        return toPage.toPage(vehicleAccessRecordPOIPage, vehicleAccessRecordConverter.vehicleAccessRecordPOList2VehicleAccessRecordBOList(vehicleAccessRecordPOIPage.getRecords()));
    }

    @Override
    public IPage<VehicleAccessRecordBO> accessRecordForPlateNumberDuplicateRemoval(QueryVehicleAccessRecordSecondBO queryVehicleAccessRecordSecondBO, PageBO pageBO) {

        IPage<Integer> integerIPage = vehicleAccessRecordMapper.queryAccessRecordsForPlateNumberDuplicateRemoval(pageBO.toPage(), queryVehicleAccessRecordSecondBO);

        List<Integer> integerList = integerIPage.getRecords();
        List<VehicleAccessRecordPO> vehicleAccessRecordPOList;
        if (integerList.isEmpty()) {
            vehicleAccessRecordPOList = new ArrayList<>();
        } else {
            vehicleAccessRecordPOList = vehicleAccessRecordMapper.queryAccessRecordsByIds(toPageBO.toPageBOForAccessRecord(pageBO).toPage(), integerList);
        }
        return toPage.toPage(integerIPage, vehicleAccessRecordConverter.vehicleAccessRecordPOList2VehicleAccessRecordBOList(vehicleAccessRecordPOList));
    }

    @Override
    public Integer accessRecordForCount(QueryVehicleAccessRecordForCountBO queryVehicleAccessRecordForCountBO) {
        return vehicleAccessRecordMapper.accessRecordForCount(queryVehicleAccessRecordForCountBO);
    }

    @Override
    public Integer accessRecordForCountWU(QueryVehicleAccessRecordForCountBO queryVehicleAccessRecordForCountBO) {
        return vehicleAccessRecordMapper.accessRecordForCountWU(queryVehicleAccessRecordForCountBO);
    }

    @Override
    public VehicleIntegratedConfigBO enterCarRecord(CarInDataCoSonDTO carInDataCoSonDTO) {
        VehicleAccessRecord vehicleAccessRecord = new VehicleAccessRecord();
        vehicleAccessRecord.setCardType(VehicleCardTypeEnum.toVehicleCardTypeEnumByCoSon(Integer.valueOf(carInDataCoSonDTO.getCarType())).getId()
        );
        vehicleAccessRecord.setParkId(carInDataCoSonDTO.getKey());
        vehicleAccessRecord.setPlateNumber(carInDataCoSonDTO.getCarNo());
        vehicleAccessRecord.setEnterPassageName(carInDataCoSonDTO.getGateName());
        vehicleAccessRecord.setRecordId(carInDataCoSonDTO.getOrderNo());
        vehicleAccessRecord.setEnterPictureUrl(carInDataCoSonDTO.getImgUrl());
        Date date = DateUtil.parse(carInDataCoSonDTO.getEnterTime());
        vehicleAccessRecord.setEnterTime(date);

        VehicleAccessRecord vehicleAccessRecord1 = new VehicleAccessRecord();
        vehicleAccessRecord1.setProjectId(vehicleAccessRecord.getProjectId());
        vehicleAccessRecord1.setPlateNumber(vehicleAccessRecord.getPlateNumber());
        List<VehicleAccessRecord> list = vehicleAccessRecordController.list(vehicleAccessRecord1);
        Integer size = list.size();
        if (size != 0 && (list.get(size - 1).getStatus()).equals(0)) {
            throw new BusinessException("该车辆已有入场记录");
        }
        vehicleAccessRecord.setStatus(0);
        VehicleIntegratedConfigBO vehicleIntegratedConfigBO = queryDeviceService.queryIntegratedConfigFromParkId(vehicleAccessRecord.getParkId());
        vehicleAccessRecord.setProjectId(vehicleIntegratedConfigBO.getVehicleSystemInfoBO().getProjectId());
        vehicleAccessRecordMapper.insert(vehicleAccessRecord);
        return vehicleIntegratedConfigBO;
    }

    @Override
    public VehicleIntegratedConfigBO outCarRecord(CarOutDataCoSonDTO carOutDataCoSonDTO) {
        VehicleAccessRecord vehicleAccessRecord = new VehicleAccessRecord();
        vehicleAccessRecord.setCardType(VehicleCardTypeEnum.toVehicleCardTypeEnumByCoSon(Integer.valueOf(carOutDataCoSonDTO.getCarType())).getId()
        );
        vehicleAccessRecord.setParkId(carOutDataCoSonDTO.getKey());
        vehicleAccessRecord.setPlateNumber(carOutDataCoSonDTO.getCarNo());
        vehicleAccessRecord.setExitPassageName(carOutDataCoSonDTO.getGateName());
        vehicleAccessRecord.setRecordId(carOutDataCoSonDTO.getOrderNo());
        vehicleAccessRecord.setExitPictureUrl(carOutDataCoSonDTO.getImgUrl());
        Date date = DateUtil.parse(carOutDataCoSonDTO.getOutTime());
        vehicleAccessRecord.setExitTime(date);
        VehicleIntegratedConfigBO vehicleIntegratedConfigBO = queryDeviceService.queryIntegratedConfigFromParkId(vehicleAccessRecord.getParkId());
        vehicleAccessRecord.setProjectId(vehicleIntegratedConfigBO.getVehicleSystemInfoBO().getProjectId());

        VehicleAccessRecord vehicleAccessRecord1 = new VehicleAccessRecord();
        vehicleAccessRecord1.setProjectId(vehicleAccessRecord.getProjectId());
        vehicleAccessRecord1.setPlateNumber(vehicleAccessRecord.getPlateNumber());
        List<VehicleAccessRecord> list = vehicleAccessRecordController.list(vehicleAccessRecord1);
        Integer size = list.size();
        if (size != 0 && (list.get(size - 1).getStatus()).equals(1)) {
            throw new BusinessException("该车辆已有出场记录");
        }
        if ((list.get(size - 1).getStatus()).equals(0)) {
            vehicleAccessRecord.setId(list.get(size - 1).getId());
            vehicleAccessRecord.setStatus(1);
            vehicleAccessRecordMapper.updateById(vehicleAccessRecord);
        }
        return vehicleIntegratedConfigBO;
    }

    @Override
    public List<VehicleAccessRecord> list(VehicleAccessRecord vehicleAccessRecord) {
        QueryWrapper<VehicleAccessRecord> wrapper = new QueryWrapper<>();
        if (Objects.nonNull(vehicleAccessRecord.getProjectId())) {
            wrapper.eq("project_id", vehicleAccessRecord.getProjectId());
        }
        if (Objects.nonNull(vehicleAccessRecord.getPlateNumber())) {
            wrapper.like("plate_number", vehicleAccessRecord.getPlateNumber());
        }
        return vehicleAccessRecordMapper.selectList(wrapper);
    }

    /**
     * 获取最新的进或出记录
     *
     * @param vehicleAccessRecordSecondDTO
     * @return
     */
    @Override
    public IPage<VehicleAccessRecordSecondVO> accessRecordForInOut(VehicleAccessRecordSecondDTO vehicleAccessRecordSecondDTO) {
        Page<VehicleAccessRecord> vehicleAccessRecordPage = new Page<>(vehicleAccessRecordSecondDTO.getPageNumber(), vehicleAccessRecordSecondDTO.getPageSize());
        Page<VehicleAccessRecord> page = this.page(vehicleAccessRecordPage, conditionForInOUt(vehicleAccessRecordSecondDTO.getProjectId()));
        return toPage.toPage(page, vehicleAccessRecordConverter.toVehicleAccessRecordSecondVOList(page.getRecords()));
    }

    /**
     * 根据项目id和更新时间来获取相应的进记录或出记录
     */
    private Wrapper<VehicleAccessRecord> conditionForInOUt(Integer projectId) {
        LambdaQueryWrapper<VehicleAccessRecord> vehicleAccessRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        return vehicleAccessRecordLambdaQueryWrapper.eq(VehicleAccessRecord::getProjectId, projectId)
                .orderByDesc(VehicleAccessRecord::getUpdatedAt);
    }

    /**
     * 获取今天的进记录
     *
     * @param queryVehicleCarportBO
     * @return
     */
    @Override
    public Integer accessRecordForInFromToday(QueryVehicleCarportBO queryVehicleCarportBO) {
        LambdaQueryWrapper<VehicleAccessRecord> inWrapper = new LambdaQueryWrapper<>();
        inWrapper.eq(VehicleAccessRecord::getProjectId, queryVehicleCarportBO.getProjectId())
                .isNotNull(VehicleAccessRecord::getEnterTime);
        return getBaseMapper().selectCount(inWrapper);


    }

    /**
     * 获取今天的出记录
     *
     * @param queryVehicleCarportBO
     * @return
     */
    @Override
    public Integer accessRecordForOutFromToday(QueryVehicleCarportBO queryVehicleCarportBO) {
        LambdaQueryWrapper<VehicleAccessRecord> outWrapper = new LambdaQueryWrapper<>();
        outWrapper.eq(VehicleAccessRecord::getProjectId, queryVehicleCarportBO.getProjectId())
                .isNotNull(VehicleAccessRecord::getExitTime);
        return  getBaseMapper().selectCount(outWrapper);
    }

    @Override
    public List<AccessRecordTrendVo> accessRecordTrendThirtyDays(AccessTrendQuery query) {
        List<Integer> projectIds = new ArrayList<>();
        if(query.getEnterpriseId() != null) {
            ProjectQuery projectQuery = new ProjectQuery();
            projectQuery.setEnterpriseId(query.getEnterpriseId());
            List<Project> projects = iProjectService.list(projectQuery, null);
            projectIds.addAll(projects.stream().map(Project::getId).collect(Collectors.toList()));
        }
        if(query.getProjectId() != null) {
            projectIds.add(query.getProjectId());
        }
        if(ChkUtil.isNull(projectIds)) {
            throw new BusinessException("项目id不能为空");
        }

        Date now = AboutDateUtil.theSameDayOfDate(new Date());
        Date startTime = AboutDateUtil.dateMinusDay(now, 29);

        List<VehicleAccessRecord> vehicleAccessRecords = this.list(new LambdaQueryWrapper<VehicleAccessRecord>().
                in(VehicleAccessRecord::getProjectId, projectIds).
                ge(VehicleAccessRecord::getCreatedAt, startTime));

        LinkedList<AccessRecordTrendVo> accessRecordTrendVos = new LinkedList<>();
        Date endTime = new Date();

        for(int i = 0; i < 30 ; i++) {
            AccessRecordTrendVo accessRecordTrendVo = new AccessRecordTrendVo();
            accessRecordTrendVo.setDate(DateUtil.formatDate(endTime));

            Date finalEndTime = endTime;
            Date finalStartTime = DateUtil.beginOfDay(endTime);
            List<VehicleAccessRecord> vehicleAccessRecordInList = vehicleAccessRecords.stream().filter(vehicleAccessRecord -> {
                if (vehicleAccessRecord.getEnterTime() != null && vehicleAccessRecord.getEnterTime().before(finalEndTime) &&
                        (vehicleAccessRecord.getEnterTime().after(finalStartTime) || vehicleAccessRecord.getEnterTime().equals(finalStartTime))) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());
            if(vehicleAccessRecordInList.size() != 0){
                accessRecordTrendVo.setIn(vehicleAccessRecordInList.size());
            }

            List<VehicleAccessRecord> vehicleAccessRecordOutList = vehicleAccessRecords.stream().filter(vehicleAccessRecord -> {
                if (vehicleAccessRecord.getExitTime() != null && vehicleAccessRecord.getExitTime().before(finalEndTime) &&
                        (vehicleAccessRecord.getExitTime().after(finalStartTime) || vehicleAccessRecord.getExitTime().equals(finalStartTime))) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());
            if(vehicleAccessRecordOutList.size() != 0){
                accessRecordTrendVo.setOut(vehicleAccessRecordOutList.size());
            }
            accessRecordTrendVo.setTotal(accessRecordTrendVo.getIn() + accessRecordTrendVo.getOut());

            endTime = AboutDateUtil.dateMinusDay(endTime, 1);

            accessRecordTrendVos.addFirst(accessRecordTrendVo);
        }

        return accessRecordTrendVos;
    }

}

